/**
 * @defgroup    ota
 * @ingroup     common
 * @brief       Simple OTA interpreter
 * @{
 */

#ifndef OTA_H
#define OTA_H

#include <stdbool.h>
#include <stdint.h>
#include "global.h"

#ifdef __cplusplus
extern "C" {
#endif

/* 支持命令数据最大长度 */
#ifndef OTA_COMMAND_BUFFER_MAX_SIZE
#define OTA_COMMAND_BUFFER_MAX_SIZE (128)
#endif

/* 支持命令参数最大个数 */
#ifndef OTA_COMMAND_PARAMS_MAX_SIZE
#define OTA_COMMAND_PARAMS_MAX_SIZE (10)
#endif

/* 支持SDRAM缓存数据最大长度 */
#ifndef OTA_FIRMWARE_SDRAM_MAX_SIZE
#define OTA_FIRMWARE_SDRAM_MAX_SIZE (10*1024)
#endif

enum ota_type {
    type_dis = 0,
    type_ble,
    type_ecu,
    type_bms,
    type_iot = 6,
    type_gps = 7,
};

/**
 * @brief           Check firmware
 *
 * @param[in]       type   Type of firmware.
 * @param[in]       size   Size of firmware.
 * @param[in]       save   Save the firmware to FLASH or SDRAM.
 * @param[in]       addr   Start address of the firmware data.
 *
 * @return 0 on success
 * @return Anything else on failure
 */
typedef int (*ota_check_t)(unsigned int type, unsigned int size, unsigned int save, unsigned addr);

/**
 * @brief           Update firmware
 *
 * @param[in]       type   Type of firmware.
 * @param[in]       size   Size of firmware.
 * @param[in]       save   Save the firmware to FLASH or SDRAM.
 * @param[in]       addr   Start address of the firmware data.
 *
 * @return 0 on success
 * @return -EBUSY on execute
 * @return Anything else on failure
 */
typedef int (*ota_update_t)(unsigned int type, unsigned int size, unsigned int save, unsigned addr);


/**
 * @brief   Define OTA fireware
 *
 * Example:
 *
 * ```.c
 * #include "ota.h"
 * static int my_command_handler(int argc, char **argv) {
 *   // ...
 * }
 * OTA_COMMAND_ADD(my_command, my_command_handler);
 * ```
 */
#define OTA_FIRMWARE_ADD(_type, _size, _save, _addr, _check, _update) \
    XFA_CONST(ota_firmware_xfa, 0) ota_firmware_xfa_t _xfa_ ## ota ## _type = { \
        .type = _type, \
        .size = _size, \
        .save = _save, \
        .addr = _addr, \
        .check = &_check, \
        .update = &_update, \
    }

/* OTA初始化函数 */
int ota_initize(int (*read)(void *data, int len), int (*write)(void *data, int len), unsigned int (*time_msec)(void));

/* OTA处理函数 */
int ota_process(bool *is_ota, uint8_t one_byte);

/* OTA状态函数 */
int ota_is_idle(void);

int iot_upgrade_request(unsigned int type, unsigned int size, unsigned int save, unsigned int addr);

ssize_t app_flash_read(ssize_t len, uint8_t *buf, uint32_t offset);

int8_t app_flash_flush(void);

int32_t app_flash_write(uint64_t ota_received, uint32_t len, unsigned char *buf);
#ifdef __cplusplus
}
#endif

#endif /* OTA_H */
/** @} */
